/**
 * 测试数据库的封装操作
 */

// 因为操作数据库最耗时的是连接数据库，所以对数据库进行封装，解决重复连接数据库问题
// 简单封装后存在多个实例化重复调用数据连接的问题，所以在封装时要解决。
const { MongoClient, ObjectId } = require('mongodb'); // 引入数据库
// 配置
const config_db = {
  dbUrl: 'mongodb://localhost:27017',
  dbName: 'test'
}

/**
 * 封装db库
 */

class Db {
  // 创建一个静态方法，解决多个实例重复连接数据库的问题
  // 比如实例testDb1已经连接过数据库了，
  // 但是实例testDb2仍然会调用connect方法 去连接数据库，浪费了性能
  // 我们需要的是，当前面有实例连接过数据库时， 
  // 数据库处于连接状态，那么以后的实例都不需要再去连接了
  static getInstance() {
    if(!Db.instance) { // 如果不存在实例
      Db.instance = new Db(); // 就创建实例
    }
    return Db.instance;
  }
  constructor() {
    // 设置一个属性 解决某个实例上多个方法重复调用数据库连接的问题
    // 比如实例testDb已经连接过数据库了，那么在用find查询时，就不要再去重复连接了
    this.dbClient = ''; 

    this.connect(); // 初始化的时候就连接数据库
  }

  connect() { // 连接数据库
    return new Promise((resolve, reject) => {
      if(!this.dbClient) { // 如果dbClient不存在，就说明没调用过
        MongoClient.connect(config_db.dbUrl, (err, client) => {
          if(err) {
            reject(err);
          } else {
            this.dbClient = client.db(config_db.dbName);
            resolve(this.dbClient);
          }
        })
      } else { // 如果已经存在 说明被调用过了
        return resolve(this.dbClient);
      }
    })
  }

  // 获取_id，因为查询时用到的_id的值是ObjectId()类型的数据
  getObjectId(id) { 
    return new ObjectId(id);
  }

  // 删除数组内的某个值
  deleteDeep(collectionName, query, datas) {
    return new Promise((resolve, reject) => {
      this.connect()
        .then(db => {
          db.collection(collectionName)
            .updateOne(query, { $pull: datas }, (err, data) => {
            if (err) {
              reject(err)
            } else {
              resolve(data)
            }
          })
        })
      .catch(err => reject(err))
    })
  }


}

const DB = Db.getInstance();
DB.deleteDeep('users', {uname: 'dilireba'}, {'friend': {name: 'xiaoming'}})
  .then(data => console.log(data))
  .catch(err => console.log(err))

module.exports = Db.getInstance();